package com.zwps.common.tool.crypto;

import cn.hutool.core.util.HexUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.crypto.BCUtil;
import cn.hutool.crypto.SmUtil;
import cn.hutool.crypto.asymmetric.KeyType;
import cn.hutool.crypto.asymmetric.SM2;
import org.bouncycastle.crypto.params.ECPrivateKeyParameters;
import org.bouncycastle.crypto.params.ECPublicKeyParameters;
import org.bouncycastle.jcajce.provider.asymmetric.ec.BCECPublicKey;
import java.security.PrivateKey;
import java.security.PublicKey;

/**
 * 国密SM2加解密
 * 配合前端使用SM2加密js库（sm-crypto）
 * @ClassName: Sm2Tool
 * @Description:
 * @author lyh
 * @date 2023年6月21日 上午9:26:55
 *
 */
public class Sm2Tool {

    /**
     * 生成公私钥对
     * 
     * @return
     */
    public static SMKeyPair genKeyPair() {
        SM2 sm2 = SmUtil.sm2();
        String priKey = HexUtil.encodeHexStr(BCUtil.encodeECPrivateKey(sm2.getPrivateKey()));
        String pubKey = HexUtil.encodeHexStr(((BCECPublicKey) sm2.getPublicKey()).getQ().getEncoded(false));
        return new SMKeyPair(priKey, pubKey);
    }

    /**
     * SM2加密算法
     * 
     * @param publicKey 公钥
     * @param text      数据
     * @return
     */
    public static String encrypt(String publicKey, String text) {
        ECPublicKeyParameters ecPublicKeyParameters = null;
        // 这里需要根据公钥的长度进行加工
        if (publicKey.length() == 130) {
            // 这里需要去掉开始第一个字节 第一个字节表示标记
            publicKey = publicKey.substring(2);
            String xhex = publicKey.substring(0, 64);
            String yhex = publicKey.substring(64, 128);
            ecPublicKeyParameters = BCUtil.toSm2Params(xhex, yhex);
        } else {
            PublicKey p = BCUtil.decodeECPoint(publicKey, SmUtil.SM2_CURVE_NAME);
            ecPublicKeyParameters = BCUtil.toParams(p);
        }
        // 创建sm2 对象
        SM2 sm2 = new SM2(null, ecPublicKeyParameters);
        // 公钥加密
        return sm2.encryptHex(text, KeyType.PublicKey);
    }

    /**
     * SM2加密算法
     * 
     * @param publicKey 公钥
     * @param text      明文数据
     * @return
     */
    public static String encrypt(PublicKey publicKey, String text) {
        ECPublicKeyParameters ecPublicKeyParameters = BCUtil.toParams(publicKey);
        // 创建sm2 对象
        SM2 sm2 = new SM2(null, ecPublicKeyParameters);
        // 公钥加密
        return sm2.encryptHex(text, KeyType.PublicKey);
    }

    /**
     * SM2解密算法
     * 
     * @param privateKey 私钥
     * @param cipherData 密文数据
     * @return
     */
    public static String decrypt(String privateKey, String cipherData) {
        ECPrivateKeyParameters ecPrivateKeyParameters = BCUtil.toSm2Params(privateKey);
        // 创建sm2 对象
        SM2 sm2 = new SM2(ecPrivateKeyParameters, null);
        // 私钥解密
        return StrUtil.utf8Str(sm2.decrypt(cipherData, KeyType.PrivateKey));
    }

    /**
     * SM2解密算法
     * 
     * @param privateKey 私钥
     * @param cipherData 密文数据
     * @return
     */
    public static String decrypt(PrivateKey privateKey, String cipherData) {
        ECPrivateKeyParameters ecPrivateKeyParameters = BCUtil.toParams(privateKey);
        // 创建sm2 对象
        SM2 sm2 = new SM2(ecPrivateKeyParameters, null);
        // 私钥解密
        return StrUtil.utf8Str(sm2.decrypt(cipherData, KeyType.PrivateKey));
    }


    public static void main(String[] args) {
//        String encrypt = decrypt("00f0d0d458dda6ae65fb763b72ee15e7f69d0243a8059f89d0f18ab52add2ff125", "04166a6237b7d99d3ceb7bdb29a80086d11aab2b9e5ed628c1b83455e3bbcf93f85a2dfdecb27dba3e229ac4661f9946f175d23e5badadac54ab9b1133efe6494dc8a5ddb02bcf171e5a8159c252333656537e2132054e2736f64fdb65ca56a27c0e3e9fb659dfa9ca393807b6916eb5");
//        System.out.println(encrypt);
        System.out.println(encrypt("04669bccb6db06b1f7182897f49f24e03872a40a707b847d7ffeeca1f548f890b526decf0e878e15201cb4f3b01fb6f0a70dd6220e57126f4f7a2517b985fae9da", "Abcd@123"));
//        String encrypt1 = decrypt("00f0d0d458dda6ae65fb763b72ee15e7f69d0243a8059f89d0f18ab52add2ff125", "04175da1183a9b9506e7221f6710339300fab01877798774b634d11be73de222b45448fc2f0084e63c5ea0836ee192d9a063f116826784ccb39f0c21ce60bb08a1129ca2486efe4eb7052a082c65c19397545db866ec96063c6aa1ae208fba5cfed0b6b5285fd56711df99ea007e2d");
//
//        System.out.println(encrypt1);
    }
    /**
     * 私钥签名
     * 
     * @param privateKey 私钥
     * @param content    待签名内容
     * @return
     */
    public static String sign(String privateKey, String content) {
        ECPrivateKeyParameters ecPrivateKeyParameters = BCUtil.toSm2Params(privateKey);
        // 创建sm2 对象
        SM2 sm2 = new SM2(ecPrivateKeyParameters, null);
        return sm2.signHex(HexUtil.encodeHexStr(content));
    }

    /**
     * 验证签名
     * 
     * @param publicKey 公钥
     * @param content   待签名内容
     * @param sign      签名值
     * @return
     */
    public static boolean verify(String publicKey, String content, String sign) {
        ECPublicKeyParameters ecPublicKeyParameters = null;
        // 这里需要根据公钥的长度进行加工
        if (publicKey.length() == 130) {
            // 这里需要去掉开始第一个字节 第一个字节表示标记
            publicKey = publicKey.substring(2);
            String xhex = publicKey.substring(0, 64);
            String yhex = publicKey.substring(64, 128);
            ecPublicKeyParameters = BCUtil.toSm2Params(xhex, yhex);
        } else {
            PublicKey p = BCUtil.decodeECPoint(publicKey, SmUtil.SM2_CURVE_NAME);
            ecPublicKeyParameters = BCUtil.toParams(p);
        }
        // 创建sm2 对象
        SM2 sm2 = new SM2(null, ecPublicKeyParameters);
        return sm2.verifyHex(HexUtil.encodeHexStr(content), sign);
    }

//    public static void main(String[] args) {
//        SMKeyPair smKeyPair = genKeyPair();
//        String priKey = smKeyPair.getPriKey();
//        System.out.println("私钥" + priKey);
//        String pubKey = smKeyPair.getPubKey();
//        System.out.println("公钥" + pubKey);
//        // 明文
//        String text = "123123123";
//        System.out.println("测试明文文本" + text);
//        // 签名测试
//        String sign = sign(priKey, text);
//        System.out.println("生成签名" + sign);
//        // 验签测试
//        boolean verify = verify(pubKey, text, sign);
//        System.out.println("验签结果" + verify);
//
//        // 加解密测试
//        String encryptData = encrypt(pubKey, text);
//        System.out.println("加密结果" + encryptData);
//        String decryptData = decrypt(priKey, encryptData);
//        System.out.println("解密结果" + decryptData);
//
//    }
}
